#pragma once
#include <windows.h>
#include <utility>
#include <stdexcept>
#include <system_error>

namespace CppWinApi::Windows
{
	class ProcessInformation
	{
		HANDLE mProcess = nullptr;
		HANDLE mThread = nullptr;
		DWORD mProcessId = 0;
		DWORD mThreadId = 0;

	public:
		// 默认构造函数
		ProcessInformation() = default;

		// 从 PROCESS_INFORMATION 构造（接管所有权）
		explicit ProcessInformation(PROCESS_INFORMATION& pi) noexcept : mProcess(pi.hProcess),
			mThread(pi.hThread),
			mProcessId(pi.dwProcessId),
			mThreadId(pi.dwThreadId) {}

		// 禁止拷贝构造（避免重复关闭句柄）
		ProcessInformation(const ProcessInformation&) = delete;
		ProcessInformation& operator=(const ProcessInformation&) = delete;

		// 移动构造
		ProcessInformation(ProcessInformation&& other) noexcept : mProcess(std::exchange(other.mProcess, nullptr)),
			mThread(std::exchange(other.mThread, nullptr)),
			mProcessId(std::exchange(other.mProcessId, 0)),
			mThreadId(std::exchange(other.mThreadId, 0)) {}

		// 移动赋值
		ProcessInformation& operator=(ProcessInformation&& other) noexcept
		{
			if (this != &other)
			{
				Close(); // 先释放当前资源
				mProcess = std::exchange(other.mProcess, nullptr);
				mThread = std::exchange(other.mThread, nullptr);
				mProcessId = std::exchange(other.mProcessId, 0);
				mThreadId = std::exchange(other.mThreadId, 0);
			}
			return *this;
		}

		// 析构函数
		~ProcessInformation()
		{
			Close();
		}

		// 显式关闭所有句柄
		void Close() noexcept
		{
			if (mProcess)
			{
				CloseHandle(mProcess);
				mProcess = nullptr;
			}
			if (mThread)
			{
				CloseHandle(mThread);
				mThread = nullptr;
			}
			mProcessId = 0;
			mThreadId = 0;
		}

		// 转换为 PROCESS_INFORMATION（不转移所有权）
		PROCESS_INFORMATION Get() const noexcept
		{
			PROCESS_INFORMATION pi = {};
			pi.hProcess = mProcess;
			pi.hThread = mThread;
			pi.dwProcessId = mProcessId;
			pi.dwThreadId = mThreadId;
			return pi;
		}

		// 转换为 PROCESS_INFORMATION（转移所有权）
		PROCESS_INFORMATION Release() noexcept
		{
			PROCESS_INFORMATION pi = {};
			pi.hProcess = std::exchange(mProcess, nullptr);
			pi.hThread = std::exchange(mThread, nullptr);
			pi.dwProcessId = std::exchange(mProcessId, 0);
			pi.dwThreadId = std::exchange(mThreadId, 0);
			return pi;
		}

		// 获取各个成员
		HANDLE GetProcess() const noexcept { return mProcess; }
		HANDLE GetThread() const noexcept { return mThread; }
		DWORD GetProcessId() const noexcept { return mProcessId; }
		DWORD GetThreadId() const noexcept { return mThreadId; }

		// 检查是否有效
		explicit operator bool() const noexcept
		{
			return mProcess != nullptr || mThread != nullptr;
		}

		/// <summary>
		/// 等待一个进程退出
		/// </summary>
		/// <param name="timeout">超时时间</param>
		/// <param name="exitCode">退出码</param>
		/// <returns>返回等待状态</returns>
		DWORD WaitForExit(DWORD* exitCode, DWORD timeout = INFINITE) const {

			DWORD result = WaitForSingleObject(mProcess, timeout);

			if (!exitCode) {
				throw std::invalid_argument("exitCode pointer cannot be null");
			}

			if (result == WAIT_FAILED) {
				throw std::system_error(
					GetLastError(),
					std::system_category(),
					"WaitForSingleObject failed");
			}
			else if (result == WAIT_TIMEOUT) {
				return WAIT_TIMEOUT;
			}

			if (!GetExitCodeProcess(mProcess, exitCode)) {
				throw std::system_error(
					GetLastError(),
					std::system_category(),
					"GetExitCodeProcess failed");
			}

			return result;
		}
	};
}